package com.cheng.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.cheng.entity.MsgResponse;
import com.cheng.entity.Tieba;
import com.cheng.entity.Users;
import com.cheng.service.TiebaService;
import com.cheng.service.UsersService;
import com.cheng.utils.CusAccessObjectUtil;
import com.cheng.utils.EmailUtil;
import com.cheng.utils.TiebaSign;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.cheng.utils.TiebaUtil.checkFields;

/**
 * @author Cheng
 * @since 2019-07-18
 */
@RestController
@CrossOrigin(origins = "*", allowCredentials = "true")
@RequestMapping("/tieba")
@SuppressWarnings("all")
public class TiebaController {

    private static final Logger logger = LoggerFactory.getLogger(TiebaController.class);

    @Autowired
    private TiebaSign tiebaSign;
    @Autowired
    private TiebaService tiebaService;
    @Autowired
    private UsersService usersService;
    @Autowired
    private EmailUtil emailUtil;

    private PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    private int execute = 0;

    //每1分钟执行一次
    @Scheduled(cron = "0 0/1 * * * ?")
    public void tiebaTask() throws Exception {
        try {
            List<Tieba> list = tiebaService.selectList(Condition.create().eq("validity", 1)
                    .andNew().lt("finish_time", new SimpleDateFormat("yyyy-MM-dd").format(new Date())).or().isNull("finish_time"));
            for (Tieba tieba : list) {
                System.out.println("Sign:" + tieba);
                sign(tieba);
                System.out.println("execute: " + ++execute);
            }
        } catch (Exception e) {
            logger.error("fail to executor task ", e);
        }
    }

    /**
     * 获取关注贴吧到数据库
     *
     * @param tieba
     * @throws Exception
     */
    public JSONArray updateForum(Tieba tieba) throws Exception {
        String bduss = tieba.getBduss();
        cm.setMaxTotal(200);             //    设置最大连接数
        cm.setDefaultMaxPerRoute(10);    //    设置每个主机的并发数
        String tbstr = tiebaSign.verification(bduss);
        if (tbstr == null) {
            tieba.setValidity(0);
            System.out.println("验证失败更新字段:" + tiebaService.update(tieba, Condition.create().eq("bduss", bduss)));
            return null;
        }
        int pageNum = 1;
        int pageSize = 400;
        JSONArray forumArray = new JSONArray();
        JSONObject forumJson = new JSONObject();
        do {
            logger.info("pageNum :" + pageNum + ",pageSize:" + pageSize);
            JSONObject result = (JSONObject) JSON.parse(tiebaSign.getForums(bduss, cm, pageNum, pageSize));
//            logger.info("获取所有贴吧列表的返回结果:" + result);
            if (result.getString("error_code").equals("110001")) {
                logger.info("当前百度云服务器异常,获得数据错误");
                pageNum += 1;
                continue;
            }
            JSONObject forum_list = result.getJSONObject("forum_list");
//            System.out.println("贴吧总表：" + forum_list);
            JSONArray jsonArray = forum_list.getJSONArray("non-gconforum");
//            System.out.println("获取列表成功>>>>>" + jsonArray);
            for (int i = 0; i < jsonArray.size(); i++) {
                logger.info("第 " + pageNum + "一个,第" + i + "个贴吧,名称是" + jsonArray.getJSONObject(i).getString("name"));
            }
            int size = (int) (forumJson.get("size") == null ? 0 : forumJson.get("size"));
            forumJson.put("size", jsonArray.size() + size);
            for (Object o : jsonArray) {
                JSONObject forumOne = new JSONObject();
                JSONObject forum = (JSONObject) JSON.toJSON(o);
                String id = forum.getString("id");
                String name = forum.getString("name");
                forumOne.put("id", id);
                forumOne.put("name", name);
                forumOne.put("status", 0);
                forumArray.add(forumOne);
            }
            if (forum_list.containsKey("gconforum")) {
                System.out.println("特权贴吧获取中>>>");
                JSONArray gconforum = forum_list.getJSONArray("gconforum");
                for (Object o : gconforum) {
                    JSONObject forumOne = new JSONObject(true);
                    JSONObject forum = (JSONObject) JSON.toJSON(o);
                    String id = forum.getString("id");
                    String name = forum.getString("name");
                    forumOne.put("id", id);
                    forumOne.put("name", name);
                    forumOne.put("status", 0);
                    forumArray.add(forumOne);
                }
            }
            // 9页 9*200 = 1800
            if (pageNum == 9) break;
            pageNum += 1;
        } while (true);
        forumJson.put("rows", forumArray);
        tieba.setForumList(forumJson.toString());
        tieba.updateById();
        return forumArray;
    }

    /*查询数据库
     * forumList是否为空->空->执行获取操作并填入
     * 遍历forumList查看状态为0的行
     * 签到为0的行->签到成功状态改为1
     * 如果签到任务出现可贴吧不存在或拉黑 标记2、3
     * 全部是1后更新finishTime为今日
     * */
    public void sign(Tieba tieba) throws Exception {
        cm.setMaxTotal(200);             //    设置最大连接数
        cm.setDefaultMaxPerRoute(10);    //    设置每个主机的并发数
        String bduss = tieba.getBduss();
        tieba.setRetryCount(tieba.getRetryCount() == null ? 0 : tieba.getRetryCount());
//        重试次数为0时说明当日第一次执行 从服务器获取贴吧列表 重试次数>0时都直接从数据库取
        if (StringUtils.isBlank(tieba.getForumList()) || tieba.getRetryCount() == 0) {
//            tieba.setForumList(tieba.getForumList().replaceAll("status\":\"[1-3]","status\":\"0"));
            JSONArray tf = updateForum(tieba);
            if (tf == null) {
                tieba.setForumList(null);
                errorSend(bduss);
                return;
            }
        }
        String tbstr = tiebaSign.verification(bduss);
        if (tbstr == null) {
            tieba.setValidity(0);
            errorSend(bduss);
            System.out.println("验证失败更新字段:" + tiebaService.update(tieba, Condition.create().eq("bduss", bduss)));
            return;
        }
        JSONObject jo = (JSONObject) JSON.parse(tieba.getForumList());
        JSONArray rows = jo.getJSONArray("rows");
        List<Map<String, Object>> rowsList = JSONArray.parseObject(rows.toString(), List.class);
//        int count = 0;
        int point = 0;
        JSONObject forumJson = new JSONObject(true);
        forumJson.put("size", rows.size());
        for (Map<String, Object> forum : rowsList) {
            if ("1".equals(forum.get("status")) || "2".equals(forum.get("status")) || "3".equals(forum.get("status"))) {
                System.out.println("跳过：" + forum.get("name"));
                continue;
            }
            String id = (String) forum.get("id");
            String name = (String) forum.get("name");
            System.out.println("正在签到" + name + "：");
            String signResult = tiebaSign.signForums(name, id, tbstr, bduss, cm);
            JSONObject result = (JSONObject) JSON.parse(signResult);
            if (signResult.contains("error_code") && signResult.contains("error_msg")) {
                String error_msg = result.getString("error_msg");
                System.out.println(">>" + error_msg);
                if (error_msg.contains("目录出问题")) {
                    forum.put("status", "2");
                } else if (error_msg.contains("已经签过")) {
                    forum.put("status", "1");
                } else if (error_msg.contains("黑名单中")) {
                    forum.put("status", "3");
                } else if (error_msg.contains("加载数据失败")) {
                    forum.put("status", "4");
                } else {
                    forum.put("status", "0");
                }
                continue;
            }
            forum.put("status", "1");
            JSONObject user_info = result.getJSONObject("user_info");
            point += Integer.valueOf(user_info.getString("sign_bonus_point"));
            System.out.println("签到成功!经验+" + user_info.getString("sign_bonus_point") + ",今天第" + user_info.getString("user_sign_rank") + "个签到");
//            count++;
        }
        forumJson.put("rows", rowsList);
        tieba.setAmount(selectRows(forumJson.getJSONArray("rows"), "1").size() + "/" + rows.size());
        tieba.setPoints(point);
        tieba.setVisitTime(new Date());
        tieba.setRetryCount(tieba.getRetryCount() + 1);
        tieba.setVisitCount(tieba.getVisitCount() + 1);
        tieba.setForumList(forumJson.toString());
        if (!rowsList.toString().contains("\"0\"")) {
            tieba.setFinishTime(new Date());
            tieba.setRetryCount(0);
        }
        tieba.updateById();
    }

    private void errorSend(String bduss) {
        List<Tieba> list = tiebaService.selectList(Condition.create().eq("bduss", bduss));
        Tieba tieba1 = list.get(0);
        Users user = usersService.selectById(tieba1.getQq());
        if (user.getEmailStatus() == 1) {
            emailUtil.simpleSend(user.getEmail(), "您的签到任务bduss已过期！请及时更新", "您的签到任务：" + tieba1.getTaskname() +
                    " 的bduss已过期，请及时更新！您也可以访问以下链接进入管理页面：http://hik.win/admin/tieba.html?qq=" + user.getQq());
        }
    }

    /**
     * 添加任务
     *
     * @param tieba
     * @return
     */
    @PostMapping("/add")
    public MsgResponse addTb(@RequestBody Tieba tieba, HttpServletRequest request) {
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);

        System.out.println("add:" + tieba);
        MsgResponse msgRespose = new MsgResponse();
        if (checkFields(tieba) == false) {
            return msgRespose.setCode(1004).setMsg("参数不能为空!");
        }
        if (!tieba.getQq().matches("[0-9]{5,}")) {
            return msgRespose.setCode(1006).setMsg("QQ为至少5位纯数字,不能有空格!");
        }
        try {
            if (tiebaSign.verification(tieba.getBduss()) == null) {
                return msgRespose.setCode(1001).setMsg("bduss验证不通过!");
            }
            List<Tieba> list = tiebaService.selectList(Condition.create().eq("bduss", tieba.getBduss()));
            if (list.size() >= 1) {
                return msgRespose.setCode(1003).setMsg("bduss已存在!");
            }
            tieba.setCreatTime(new Date()).setValidity(1);
            tieba.setIp(CusAccessObjectUtil.getIpAddress(request));
            tiebaService.insert(tieba);
        } catch (Exception e) {
            e.printStackTrace();
            return msgRespose.setCode(1002).setMsg("添加贴吧签到任务失败!");
        }
        return msgRespose.setCode(1000).setMsg("添加贴吧签到任务成功!");
    }

    /**
     * 搜索
     *
     * @param qq
     * @return
     */
    @GetMapping("/search")
    public MsgResponse search(String qq) {
        MsgResponse msgRespose = new MsgResponse();
        if (StringUtils.isBlank(qq)) {
            return msgRespose.setCode(1004).setMsg("参数不能为空!");
        }
        List<Tieba> list = tiebaService.selectList(new EntityWrapper<Tieba>().eq("qq", qq));
        for (Tieba tieba : list) {
            tieba.setBduss(null);
            tieba.setForumList(null);
            tieba.setDel(null);
            tieba.setIp(null);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("rows", list);
        msgRespose.setCode(1000).setMsg(map);
        return msgRespose;
    }

    /**
     * 修改用户
     *
     * @param tieba
     * @return
     */
    @PostMapping("/update")
    public MsgResponse update(@RequestBody(required = false) Tieba tieba) {
        MsgResponse msgRespose = new MsgResponse();
        tieba.setQq(null);
        try {
            if (StringUtils.isNotBlank(tieba.getBduss()) && tiebaSign.verification(tieba.getBduss()) == null) {
                return msgRespose.setCode(1001).setMsg("bduss验证不通过!");
            }
            tieba.setValidity(1);
            boolean b = tiebaService.updateById(tieba);
            if (b == false) {
                return msgRespose.setCode(1005).setMsg("更新失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return msgRespose.setCode(1005).setMsg("更新失败");
        }
        return msgRespose.setCode(1000).setMsg("修改成功");
    }

    /**
     * 获得更新时弹出输入框内容
     *
     * @param id
     * @return
     */
    @GetMapping("/getUpdate")
    public MsgResponse updateOne(String id) {
        MsgResponse msgRespose = new MsgResponse();
        Tieba tieba = tiebaService.selectById(id);
        Map<String, Object> map = new HashMap<>();
        map.put("id", tieba.getId());
        map.put("qq", tieba.getQq());
        map.put("taskname", tieba.getTaskname());
        return msgRespose.setCode(1000).setMsg(map);
    }

    /**
     * 查询签到错误
     *
     * @param id
     * @return
     */
    @GetMapping("/findOne")
    public MsgResponse findOne(String id) {
        MsgResponse msgRespose = new MsgResponse();
        Tieba tieba = tiebaService.selectById(id);
        String forumList = tieba.getForumList();
        JSONObject jsonObject = (JSONObject) JSONObject.parse(forumList);
        JSONObject jo = null;
        try {
            JSONArray rows = jsonObject.getJSONArray("rows");
            jo = new JSONObject();
            jo.put("finishTime", tieba.getFinishTime());
            jo.put("patherror", selectRows(rows, "2"));
            jo.put("blacklist", selectRows(rows, "3"));
            jo.put("loadfail", selectRows(rows, "4"));
//            jo.put("unknown",selectRows(rows, "0"));
        } catch (Exception e) {
            e.printStackTrace();
            return msgRespose.setCode(1002).setMsg("fail!");
        }
        return msgRespose.setCode(1000).setMsg(jo);
    }

    public JSONArray selectRows(JSONArray rows, String stat) {
        JSONArray jsonArray = new JSONArray();
        for (Object row : rows) {
            JSONObject o = (JSONObject) JSON.toJSON(row);
            String status = o.getString("status");
            if (stat.equals(status)) {
                jsonArray.add(o.getString("name"));
            }
        }
        return jsonArray;
    }
}
